package ai.assist.admin.security;

import com.alibaba.fastjson.JSON;
import ai.assist.common.annotation.PassportSSO;
import ai.assist.common.businesss.service.UserSessionService;
import ai.assist.common.context.PassportUserInfoContext;
import ai.assist.common.context.UserInfoContext;
import ai.assist.common.enums.ResponseCode;
import ai.assist.common.model.ResponseData;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;

//登录拦截器
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
@Component
public class PassportSSOInterceptor implements HandlerInterceptor {

    @Autowired
    private UserSessionService userSessionService;

    //进入Handler方法之前执行
    //可以用于身份认证、身份授权。如果认证没有通过表示用户没有登陆，需要此方法拦截不再往下执行，否则就放行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String httpMethod = request.getMethod();
        String tid = UUID.randomUUID().toString().replace("-", "");
        MDC.put("LOG_TRACK_ID", tid);
        if (httpMethod.equals(HttpMethod.GET.toString()) || httpMethod.equals(HttpMethod.POST.toString())) {
            if (handler == null || handler instanceof ResourceHttpRequestHandler) {
                return true;
            }
            Method method;
            if (handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                method = handlerMethod.getMethod();
            } else {
                return false;
            }

            //优先使用方法上的注解。
            PassportSSO passportSSO = method.getAnnotation(PassportSSO.class);
            //方法上没有PassportSSO，则使用类上的。
            if (passportSSO == null) {
                passportSSO = method.getDeclaringClass().getAnnotation(PassportSSO.class);
            }
            if (passportSSO == null) {
                return true;
            }
            if (passportSSO.ignore()) {
                if (passportSSO.needInfo()) {
                    validateAccess(passportSSO, request, response);
                }
            } else {
                String authorization = request.getHeader("authorization");
                PassportUserInfoContext.reInit(authorization);
                if (StringUtils.isEmpty(authorization)) {
                    writeNeedLogin(request, response, "登录失效！");
                    return false;
                }
                boolean validSuccess = validateAccess(passportSSO, request, response);
                if (!validSuccess) {
                    writeNeedLogin(request, response, "用户未登录或没有访问权限!");
                    return false;
                }
            }

        }
        return true;
    }

    private void writeNeedLogin(HttpServletRequest request, HttpServletResponse response, String errorMsg) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        // 允许跨域支持
        String origin = request.getHeader("Origin");
        if (origin == null) {
            response.addHeader("Access-Control-Allow-Origin", "*");
        } else {
            response.addHeader("Access-Control-Allow-Origin", origin);
        }
        response.addHeader("Access-Control-Allow-Headers", "*");
        response.addHeader("Access-Control-Allow-Credentials", "true");
        response.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
        PrintWriter writer = response.getWriter();
        writer.write(JSON.toJSONString(new ResponseData(ResponseCode.USER_NOT_LOGIN, errorMsg)));
        writer.flush();
        writer.close();
    }

    /**
     * 验证地址是否登录
     *
     * @param request
     * @return
     */
    private boolean validateAccess(PassportSSO passportSSO, HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader("authorization");
        if (StringUtils.hasText(token)) {
            UserInfoContext userInfo = userSessionService.validateTicket(token);
            if (userInfo == null) {
                return false;
            }
            if (userInfo.getRoles().contains(1L) || StringUtils.isEmpty(passportSSO.value())) {//超管不校验权限，所有权限
                PassportUserInfoContext.reInit(userInfo, token);
                return true;
            }
            //校验具体权限
            List<String> ssoPermis = Arrays.asList(passportSSO.value().split(","));
            Set<String> urls = userInfo.getPermissions();
            for (String i : ssoPermis) {
                if (urls.contains(i)) {
                    PassportUserInfoContext.reInit(userInfo, token);
                    return true;
                }
            }
        }
        return false;
    }


    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        MDC.remove("LOG_TRACK_ID");
    }

}
